/**
 *  防抖函数
 * @param {*} executorFn  要执行的函数
 * @param {*} delay  延迟执行事件
 * @param {*} immediate  第一是否需要延迟执行 默认不延迟
 * @param {*} callback  回调函数
 * @returns
 */
function debouch(executorFn, delay = 300, immediate = false, callback) {
	let timer = null
	let isInvoke = false
	function _debouch(...args) {
		if (timer) clearInterval(timer)
		if (immediate && !isInvoke) {
			let res = executorFn.apply(this, args)
			callback && callback(res)
			isInvoke = true
			timer = null
		} else {
			timer = setTimeout(() => {
				let res = executorFn.apply(this, args)
				callback && callback(res)
				isInvoke = false
				timer = null
			}, delay)
		}
	}
	_debouch.cancel = function () {
		if (timer) {
			clearInterval(timer)
			isInvoke = false
			timer = null
		}
	}
	return _debouch
}
/**
 *  节流函数
 * @param {*} executorFn 要执行的函数
 * @param {*} intervals  每次间隔的时间
 * @param {*} options (leading/tailing)   leading 第一次 要不要触发 默认 要   tailing 最后一次要不要触发 默认 不触发
 * @param {*} callback   回调函数
 * @returns
 */
function throttle(
	executorFn,
	intervals = 3000,
	options = { leading: true, tailing: true },
	callback
) {
	let startTime = 0
	const { leading, tailing } = options
	let timer = null
	function _throttle(...args) {
		const nowTime = Date.now()
		if (!startTime && !leading) startTime = nowTime
		const radomTime = intervals - (nowTime - startTime)
		if (radomTime <= 0) {
			if (timer) {
				clearInterval(timer)
				timer = null
			}
			const res = executorFn.apply(this, args)
			startTime = nowTime
			callback && callback(res)
			return
		}
		if (tailing && !timer) {
			timer = setTimeout(() => {
				timer = null
				startTime = !leading ? 0 : Date.now()
				const res = executorFn.apply(this, args)
				callback && callback(res)
			}, radomTime)
		}
	}
	_throttle.cancel = function () {
		if (timer) {
			clearInterval(timer)
			timer = null
			startTime = 0
		}
	}
	return _throttle
}

/**
 * 深拷贝
 * @param {*} origin 拷贝的对象
 * @returns
 */
function deepClone(origin, map = new Map()) {
	if (typeof origin === 'function') {
		return origin
	}
	if (origin instanceof Set) {
		return new Set([...origin])
	}
	if (origin instanceof Map) {
		return new Map([...origin])
	}
	if (typeof origin === 'symbol') {
		return Symbol(origin.description)
	}

	if (!iSObject(origin)) {
		return origin
	}
	// 解决循环引用问题
	if (map.has(origin)) {
		return map.get(origin)
	}
	let cloneObj = Array.isArray(origin) ? [] : {}
	map.set(origin, cloneObj)
	for (const key in origin) {
		if (Object.hasOwnProperty.call(origin, key)) {
			const element = origin[key]
			cloneObj[key] = deepClone(element, map)
		}
	}

	const symbolKeys = Object.getOwnPropertySymbols(origin)

	for (const key of symbolKeys) {
		const element = origin[key]
		cloneObj[key] = deepClone(element, map)
	}

	return cloneObj
}

function iSObject(obj) {
	const type = typeof obj
	return obj !== null && (type === 'object' || type === 'function')
}

/**
 *  事件总线的简单实现
 *  存储结构
 *  {
 *     eventName1: [{callback1,this }, callback2,this ]
 *     eventName2: [{callback1,this }, callback2,this ]
 *
 * }
 */

class MYEventBus {
	constructor() {
		this.eventFns = {}
	}
	on(eventNam, callback, thisArgs) {
		let handlers = this.eventFns[eventNam]
		if (!handlers) {
			handlers = []
			this.eventFns[eventNam] = handlers
		}
		handlers.push({
			callback,
			thisArgs,
		})
	}
	emit(eventNam, ...args) {
		const handlers = this.eventFns[eventNam]
		if (!handlers) return
		handlers.forEach((handler) => {
			handler.callback.apply(handler.thisArgs, args)
		})
	}
	off(eventNam, callback) {
		const handlers = this.eventFns[eventNam]
		if (!handlers) return
		this.eventFns[eventNam] = handlers.filter(
			(handler) => handler.callback !== callback
		)
	}
}

const evt = new MYEventBus()
function fn(vale) {
	console.log('on fn1', vale, this)
}
function fn2() {
	console.log('on fn2')
}
evt.on('abc', fn, 'this')
evt.on('abc', fn2)
evt.emit('abc', 111)

evt.off('abc', fn2)

evt.emit('abc', 111)

// 防抖函数

// function debouch(fn, time, immediate) {
// 	let timer = null
// 	let isInvoke = false // 标记是否要立即执行
// 	function _debouch(...args) {
// 		if (immediate && !isInvoke) {
// 			fn.apply(this, args)
// 			timer = null
// 			isInvoke = true
// 		} else {
// 			clearInterval(timer)
// 			timer = setTimeout(() => {
// 				fn.apply(this, args)
// 				timer = null
// 				isInvoke = false
// 			}, time)
// 		}
// 	}
// 	_debouch.cancel = function () {
// 		clearInterval(timer)
// 		isInvoke = false
// 		timer = null
// 	}
// 	return _debouch
// }

// 节流函数
function throttle(fn, wait, tailing) {
	let startTime = 0
	let timer = null
	return (...args) => {
		const nowTime = Date.now()
		if (nowTime - startTime > wait) {
			fn.apply(this, args)
			startTime = nowTime
		}

		if (tailing && !timer) {
			timer = setTimeout(() => {
				fn.apply(this, args)
				timer = null
			}, wait)
		}
	}
}
